#include "World.h"

using namespace std;

Anim::Anim(const char* name, int posx, int posy, int width, int height, int q, int r, int g, int b, float speed)
{

    gfx = IMG_Load(name);
    if (!gfx)
    {
        printf("Nie wczytano: %s\n", name);
    }
    else
        printf("Wczytano: %s\n", name);
    SDL_SetColorKey(gfx, SDL_SRCCOLORKEY, SDL_MapRGB(gfx->format, r, g, b));

    quantity=q;
    x=posx;
    y=posy;
    w=width;
    h=height;
    frame=0;
    this->speed=speed;
}
Anim::Anim(Anim *templ)
{
    gfx = templ->gfx;
    quantity = templ->quantity;
    x=templ->x;
    y=templ->y;
    w=templ->w;
    h=templ->h;
    frame=0;
    this->speed=templ->speed;


}
void Anim::setRect(int direction)
{
    //frame=frame%quantity;
    srcrect.x = ((int)frame)%quantity*w;
    srcrect.y = h*direction;
    srcrect.w = w;
    srcrect.h = h;
    frame+=speed;
    //if(frame>quantity) frame=frame%quantity;

}
void Anim::setRectSta(int nr)
{
    srcrect.x = (nr%quantity)*w;
    //cout << srcrect.x << endl;
    srcrect.y = h*(nr/quantity);
    //cout << srcrect.y << endl;
    srcrect.w = w;
    srcrect.h = h;
}

Gfx::Gfx(int q)
{
    which=0;
    quantity=q;
    anim = new Anim*[quantity];
}
Gfx::Gfx(Gfx *gfx)
{
    which=0;
    quantity=gfx->quantity;
    anim = gfx->anim;
}


void Gfx::blitAni(SDL_Surface *screen, int x, int y, int direction)
{
    SDL_Rect dstrect;
    anim[which]->setRect(direction);
    dstrect.x = x-anim[which]->x;
    dstrect.y = y-anim[which]->y;

    SDL_BlitSurface(anim[which]->gfx, &(anim[which]->srcrect), screen, &dstrect);
}

void Gfx::blitSta(SDL_Surface *screen, int x, int y, int type, int nr)
{
    SDL_Rect dstrect;
    anim[type]->setRectSta(nr);
    dstrect.x = x-anim[type]->x;
    dstrect.y = y-anim[type]->y;

    SDL_BlitSurface(anim[type]->gfx, &(anim[type]->srcrect), screen, &dstrect);
}


Character::Character(int posx, int posy, float sp, int maxLife)
{
    armor=strenght=direction=0;
    dead=false;
    dying=false;
    frozen=false;
    atacking=false;
    speed=sp;
    x=destx=posx;
    y=desty=posy;
    next = 0;
    //TODO: Exp dla potworków trzeba by wczytywać z pliku. Dla gracza raczej 0
    exp = 0;
    level = 1;
    maxLevel = 6;
    this->maxLife=maxLife;
    life = getMaxLife();
}

void Character::go(float posx, float posy)
{
    destx+=posx;
    desty+=posy;
}

void Character::put(float posx, float posy)
{
    if(!frozen && !atacking)
    {
        if(destx<x) vx=-1;
        else if(destx>x) vx=1;
        else if(destx==x) vx=0;
        if(desty<y) vy=-1;
        else if(desty>y) vy=1;
        else if(desty==y) vy=0;

        if(vx==0 && vy==1) direction=0;
        if(vx==-1 && vy==1) direction=1;
        if(vx==-1 && vy==0) direction=2;
        if(vx==-1 && vy==-1) direction=3;
        if(vx==0 && vy==-1) direction=4;
        if(vx==1 && vy==-1) direction=5;
        if(vx==1 && vy==0) direction=6;
        if(vx==1 && vy==1) direction=7;
        if(vx==0 && vy==0) gfx->which=3;
        else gfx->which=1;

        x+=(vx*getSpeed());
        y+=(vy*getSpeed());

        if((x-destx)*(-vx)<getSpeed()) x=destx;
        if((y-desty)*(-vy)<getSpeed()) y=desty;
    }
    else if(dying)
    {
        gfx->which=2;
        if(gfx->anim[gfx->which]->frame >= gfx->anim[gfx->which]->quantity)
        {
            dying=false;
            dead=true;
            gfx->anim[gfx->which]->speed=0;
            gfx->anim[gfx->which]->frame=gfx->anim[gfx->which]->quantity-1;
        }
    }
    else if(atacking)
    {
        gfx->which=0;
        if(gfx->anim[gfx->which]->frame >= gfx->anim[gfx->which]->quantity)
        {
            //dying=false;
            //dead=true;
            atacking=false;
            //gfx->anim[gfx->which]->speed=0;
            //gfx->anim[gfx->which]->frame=gfx->anim[gfx->which]->quantity-1;
            gfx->anim[gfx->which]->frame=0;
        }

    }
    /*if(dead)
    {

    }*/
    //gfx->blitAni(screen, x, y, direction);
    gfx->blitAni(screen, posx*64, posy*48, direction);
}

void Character::putAll(Character *charlist, float layery, float posx, float posy)
{
    //Character *tmp=this;
    while(charlist)
    {
        if((int)(charlist->y)==(int)layery) charlist->put(charlist->x-x+posx,charlist->y-y+posy);
        charlist=charlist->next;
    }
};

void Character::addGfx(int q)
{
    gfx=new Gfx(q);
}
void Character::addGfx(Gfx *g)
{
    gfx=new Gfx(g);
}
void Character::addAnim(const char* name, int posx, int posy, int width, int height, int q, int r, int g, int b, float speed, int which)
{
    gfx->anim[which] = new Anim(name, posx, posy, width, height, q, r, g, b, speed);
}
/* void addAnim(Anim *ani, int which)
{
    gfx->anim[which] = new Anim(ani);
}*/

bool Character::attack(World *world, Character *charlist, int x, int y)
{
    //charlist=charlist->next;
    while(charlist)
    {
       // if((int)this->x == (int)(world->player->x + (world->screen->w-x)/64-world->map->seex/2) && (int)this->y == (int)(world->player->y + (world->screen->h-y)/48-world->map->seey/2) && charlist!=this)
        if((int)world->player->x + x == charlist->x && (int)world->player->y + y == charlist->y && charlist!=this && !charlist->dead)
        {
            if((world->player->x-charlist->x)<1 && (world->player->x-charlist->x)>-1 && (world->player->y-charlist->y)<1 && (world->player->y-charlist->y)>-1)
            {
                this->atacking=true;
                charlist->hurt(activeWeapon->attack);
                cout << "atak! " << activeWeapon->attack << endl;
                cout << (world->player->x + x ) << " " << charlist->x << endl;
                cout << (world->player->y + y ) << " " << charlist->y << endl;
                return 1;
            }
        }
        charlist=charlist->next;
    }
    return 0;
};



void Character::hurt(int power)
{
    life-=power;
    if(life<0) this->die();
};

void Character::die()
{
    this->dying=true;
    this->frozen=true;
};

Map::Map(int seex, int seey, const char* name, Character *p, Gfx *gfx)
{
    fstream file;
    file.open(name, ios_base::in);
    file >> w;
    file >> h;
    cout << w << h << endl;
    player = p;
    tile = new Tile*[h];
    int i,k;
    for(i=0; i<h; i++)
    {
        tile[i] = new Tile[w];
    }
    int tmp;
    for(i=0; i<h; i++)
    {
        for(k=0; k<w; k++)
        {
            file >> tmp;
            //cout << tmp << " " << i << " " << k << endl;
         //   tile[i][k]=new Tile;
            tile[i][k].ground = tmp;
        }
    }
    file.close();
    terrain = gfx;
    this->seex=seex;
    this->seey=seey;

}
void Map::reload(int seex, int seey, const char* name)
{
    fstream file;
    file.open(name, ios_base::in);
    file >> w;
    file >> h;
    cout << w << h << endl;

    tile = new Tile*[h];
    int i,k;
    for(i=0; i<h; i++)
    {
        tile[i] = new Tile[w];
    }
    int tmp;
    for(i=0; i<h; i++)
    {
        for(k=0; k<w; k++)
        {
            file >> tmp;
            //cout << tmp << " " << i << " " << k << endl;
         //   tile[i][k]=new Tile;
            tile[i][k].ground = tmp;
        }
    }
    file.close();
}
void Map::blit(int x, int y, int layer, int shiftx, int shifty)
{


    x=-(64*x);
    y=-(48*y);

        for(int k=0; k<w; k++)
        {
            terrain->blitSta(screen,x+k*64+shiftx,y+layer*48+shifty,tile[layer][k].ground,tile[layer][k].imgNr);
        }

}
void Map::addGfx(int q)
{
    terrain=new Gfx(q);
}
void Map::addAnim(const char* name, int posx, int posy, int width, int height, int q, int r, int g, int b, float speed, int which)
{
    terrain->anim[which] = new Anim(name, posx, posy, width, height, q, r, g, b, speed);
}
void Map::convTerrain(const char* name)
{
    map<int,int> codes;
    fstream file(name,ios_base::in);
    int n, code, def, defnull;
    int i,k;
    file >> n;
    file >> def;
    file >> defnull;
    for(i=1; i<=n; i++)
    {
        file >> code;
        codes[code]=i;
    }
    file.close();



    for(i=0; i<h; i++)
    {
        for(k=0;k<w;k++)
        {
            if(i==0||i==h-1||k==0||k==w-1)
            {
                if(tile[i][k].ground) tile[i][k].imgNr=def;
                else tile[i][k].imgNr=defnull;
            }
            else
            {
                code=((((((((((((((((tile[i-1][k-1].ground>0)<<1)+(tile[i-1][k].ground>0))<<1)+(tile[i-1][k+1].ground>0))<<1)+(tile[i][k-1].ground>0))<<1)+(tile[i][k].ground>0))<<1)+(tile[i][k+1].ground>0))<<1)+(tile[i+1][k-1].ground>0))<<1)+(tile[i+1][k].ground>0))<<1)+(tile[i+1][k+1].ground>0);
                cout << "kod: " << code <<endl;
                if(codes[code]) tile[i][k].imgNr=codes[code]-1;
                else
                {
                    if(tile[i][k].ground) tile[i][k].imgNr=def;
                    else tile[i][k].imgNr=defnull;
                }

            }
            cout << tile[i][k].imgNr << endl;
        }
    }

}

World::World(const char* config, SDL_Surface* screenmain, int sx, int sy)
{
    int i,k;
    int tmp[10];
    float tmpf[10];
    int allamount,quantity;
    char tmptext[120];
    //char mapfile[40];
   // char gfxfile[40];
   // screen=screenmain;
   /*	this->sx = sx;
   	this->sy = sy;*/
   	maindstrect = new SDL_Rect;
    maindstrect->x = sx;
    maindstrect->y = sy;
    this->screenmain=screenmain;

    fstream file(config,ios_base::in);
    file >> tmptext >> sx >> sy;
    screen=SDL_CreateRGBSurface(SDL_HWSURFACE, sx, sy, 32, screenmain->format->Rmask,screenmain->format->Gmask,screenmain->format->Bmask,screenmain->format->Amask);

    file >> tmptext >> allamount;
    gfx=new Gfx*[allamount];
    for(i=0; i<allamount; i++)
    {
        file >> quantity;
        gfx[i]=new Gfx(quantity);
        for(k=0; k<quantity; k++)
        {

            file >> tmptext >> tmp[0] >> tmp[1] >> tmp[2] >> tmp[3] >> tmp[4] >> hex >> tmp[5] >> tmp[6] >> tmp[7] >> dec >> tmpf[0];
            gfx[i]->anim[k] = new Anim(tmptext, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmpf[0]);
            //gfx[i]->scre
        }
    }

    file >> tmptext >> tmpf[0] >> tmpf[1] >> tmpf[2] >> tmp[0] >> tmp[1];
    charlist=player=0;
    addCharacter(tmpf[0],tmpf[1],tmpf[2],tmp[0],tmp[1]);
    //cout << tmpf[0] << " " << tmpf[1] << " " << tmpf[2] << " " << tmp[0] << endl;
    player=charlist;
    file >> tmptext >> tmptext >> tmp[0];
    map = new Map(screen->w/64+2,screen->h/48+2,tmptext, player, gfx[tmp[0]]);

    addCharacter(2,2,0.1,5,0);   // TEST
    map->screen=screen;
    file >> tmptext >> tmptext;
    map->convTerrain(tmptext);

    file.close();
}
void World::addCharacter(float x, float y, float speed, int maxLife, int which)
{
    Character *tmp;
    tmp = charlist;
    charlist = new Character(x,y,speed,maxLife);
    charlist->addGfx(gfx[which]);
   /* charlist->addGfx(quantity);
    for(int i=0; i<quantity; i++)
    {
        charlist->addAnim(gfx[which]->anim[i],i);
    }*/
    charlist->screen = screen;
    charlist->next=tmp;
}
void World::mouseClick(int x, int y, int button)
{
	if (button == SDL_BUTTON_LEFT) {
    	if(player->attack(this,charlist,(x-screen->w/2)/64,(y-screen->h/2)/48))
    	{

    	}
    	else
            player->go((float)(x-screen->w/2)/64,(float)(y-screen->h/2)/48);
	}

}
void World::run()
{
    //SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0,0,0));


    // Rysujemy wsio kaflami, dziwko!
    //player->x, player->y
    /*int h=8;
    int w=8;*/
    int h=map->seey;
    int w=map->seex;
    int x=player->x;
    int y=player->y;
    Tile *tile;
    float shiftx;
    float shifty;
    shiftx=((player->x-(float)x)*64);
    shifty=((player->y-(float)y)*48);

    for(int i=0; i<h; i++)      // pseudo-3D
    {
        for(int k=0; k<w; k++)  // linie
        {
            // terrain->
            // map->terrain->blitSta(screen,x+k*64,y+i*48,map->tile[i][k].ground,map->tile[i][k].imgNr);
            tile=&map->tile[(y+i+map->h)%map->h][(x+k+map->w)%map->w];
            //map->terrain->blitSta(screen,64*k-shiftx,48*i-shifty,tile->ground,tile->imgNr); // <- to calkiem dobre, potem zobaczyc
            map->terrain->blitSta(screen,64*k-shiftx,48*i-shifty,0,tile->imgNr);

           // gfx[3]->blitSta(screen,64*k-shiftx,48*i-shifty,map->tile[(y+i+map->h)%map->h][(x+k+map->w)%map->w].ground,5);
           //if(tile->ground) gfx[3]->blitSta(screen,64*k-shiftx,48*i-shifty,tile->ground,5);
          // if(tile->ground) gfx[4]->blitSta(screen,64*k-shiftx,48*i-shifty,0,0);
        }
        player->putAll(charlist,y-h/2+i-1,w/2-1,h/2-1);
       /* for(int k=0; k<w; k++)  // linie                  // mgiełka, dużo zżera:\
        {
            // terrain->
            // map->terrain->blitSta(screen,x+k*64,y+i*48,map->tile[i][k].ground,map->tile[i][k].imgNr);
            tile=&map->tile[(y+i+map->h)%map->h][(x+k+map->w)%map->w];
          //  map->terrain->blitSta(screen,64*k-shiftx,48*i-shifty,tile->ground,tile->imgNr);
           // gfx[3]->blitSta(screen,64*k-shiftx,48*i-shifty,map->tile[(y+i+map->h)%map->h][(x+k+map->w)%map->w].ground,5);
           //if(tile->ground) gfx[3]->blitSta(screen,64*k-shiftx,48*i-shifty,tile->ground,5);
           //if(tile->ground) gfx[4]->blitSta(screen,64*k-shiftx,48*i-shifty,0,0);
           if(tile->ground) gfx[6]->blitAni(screen,64*k-shiftx,48*i-shifty,1);
        }*/
    }
   /* for(int i=0; i<h; i++)      // pseudo-3D
    {

        for(int k=0; k<w; k++)  // linie
        {
            // terrain->
            // map->terrain->blitSta(screen,x+k*64,y+i*48,map->tile[i][k].ground,map->tile[i][k].imgNr);
           // map->terrain->blitSta(screen,64*k-shiftx,48*i-shifty,map->tile[(y+i+map->h)%map->h][(x+k+map->w)%map->w].ground,map->tile[(y+i+map->h)%map->h][(x+k+map->w)%map->w].imgNr);
            if(map->tile[(y+i+map->h)%map->h][(x+k+map->w)%map->w]) gfx[3]->blitSta(screen,64*k-shiftx,48*i-shifty,map->tile[(y+i+map->h)%map->h][(x+k+map->w)%map->w].ground,5);
        }
        player->putAll(charlist,y-h/2+i,w/2,h/2);

    }*/
    //player->put(w/2,h/2);   // player na środku ekranu

    if(x<0) player->go(1,0);                //
    else if(x>map->w) player->go(-1,0);     // zabezpieczenie przed wyjściem z mapy
    if(y<0) player->go(0,1);                //
    else if(y>map->h) player->go(0,-1);     //

}
void World::draw()
{
    //SDL_Flip(screen);
    /*SDL_Rect dstrect;
    sx=x;
    sy=y;
    dstrect.x = sx;
    dstrect.y = sy;*/
    SDL_BlitSurface(screen, 0, screenmain, maindstrect);
}
